home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ADA Programming Guide
/
ADA Programming Guide.iso
/
ada_gwu
/
eval.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-01-30
|
48KB
|
1,740 lines
/*
* Copyright (C) 1985-1992 New York University
*
* This file is part of the Ada/Ed-C system. See the Ada/Ed README file for
* warranty (none) and distribution info and also the GNU General Public
* License for more details.
*/
#include "hdr.h"
#include "vars.h"
#include "attr.h"
#include "arithp.h"
#include "setp.h"
#include "errmsgp.h"
#include "nodesp.h"
#include "machinep.h"
#include "sspansp.h"
#include "chapp.h"
#include "miscp.h"
#include "smiscp.h"
#include "evalp.h"
/* Define DETAIL to break up some complicated expresssions into
* several statements to assist debugging using interactive debugger
*/
#define DETAIL
static Const const_val(Symbol);
static Const eval_lit_map(Symbol);
static Const const_fold(Node);
static Const fold_unop(Node);
static Const fold_op(Node);
static Const fold_attr(Node);
static Const fold_convert(Node);
static Const eval_qual_range(Node, Symbol);
static Const eval_real_type_attribute(Node);
static Const check_overflow(Node, Const);
static int *fl_mantissa(int);
static int *fl_emax(int);
static void insert_and_prune(Node, Const);
static Rational fx_max (Rational, Rational);
static Const test_expr(int);
extern Const int_const(), real_const(), rat_const();
extern ADA_MIN_INTEGER;
/* TBSL:provide proper link to ADA_SMALL_REAL*/
#define ADA_SMALL_REAL 0.1
static Const const_val(Symbol obj) /*;const_val*/
{
/* Return the constant value of the object if it has one;
* else return om.
* The constant value of a user-defined constant is derived from
* its SIGNATURE, when this is a constant value.
* The constant value of a literal is obtained from the literal map
* of its type.
*/
Tuple sig;
if (cdebug2 > 3) TO_ERRFILE("const_val");
if (is_literal(obj)) return eval_lit_map(obj);
sig = SIGNATURE(obj);
if( is_constant(obj) && is_scalar_type(TYPE_OF(obj))
&& N_KIND((Node)sig) == as_ivalue) {
return (Const) N_VAL((Node)sig);
/* TBSL: could be static but not constant folded yet. */
}
else return const_new(CONST_OM);
}
static Const eval_lit_map(Symbol obj) /*;eval_lit_map*/
{
Symbol typ;
Tuple tup;
int i;
typ = TYPE_OF(obj);
tup = (Tuple) literal_map(typ);
for (i = 1; i <= tup_size(tup); i += 2) {
if (ORIG_NAME(obj) == (char *)0) continue;
if (streq(tup[i], ORIG_NAME(obj)))
return int_const((int)tup[i+1]);
}
return const_new(CONST_OM);
/*(return literal_map(TYPE_OF(obj))(original_name(obj));*/
}
void eval_static(Node node) /*;eval_static*/
{
/* Top level evaluation of static expressions and constant folding. The
* recursive procedure const_fold is invoked, and a top-level range
* check on numeric results is performed.
*/
/* If the node type is set to as_ivalue, the the N_VAL field will
* be a Const.
*/
Const result;
result = const_fold(node);
if (result->const_kind != CONST_OM)
check_overflow(node, result);
}
static Const const_fold(Node node) /*;const_fold*/
{
/* This recursive procedure evaluates expressions, when static.
* If node is static, its actual value is returned, and the node is
* modified to be an ivalue. Otherwise const_fold returns om, and node
* is untouched. If the static evaluation shows that the expression
* would raise an exception, a ['raise' exception] value is produced
* and placed on the tree.
*/
Fortup ft1;
Node expn, index_list, index, discr_range;
Const result;
Node opn;
Node n2, op_range;
Symbol sym, op_type;
/* */
#define is_simple_value(t) ((t)->const_kind == CONST_INT \
|| (t)->const_kind == CONST_UINT || (t)->const_kind == CONST_REAL)
if (cdebug2 > 3) { }
switch (N_KIND(node)) {
case(as_simple_name):
result = const_val(N_UNQ(node));
break;
case(as_ivalue):
result = (Const) N_VAL(node);
break;
case(as_int_literal):
/* TBSL: assuming int literal already converted check this Const*/
result = (Const) N_VAL(node);
break;
case(as_real_literal):
/*TBSL: assuming real literal already converted */
result = (Const) N_VAL(node);
break;
case(as_string_ivalue):
/* Will be static if required type has static low bound.*/
/* indx := index_type(N_TYPE(node));
* [-, lo_exp, -] := signature(indx);
* * Move this test to the expander, once format of aggregates is known.
* if is_static_expr(lo_exp) then
* lob := N_VAL(lo_exp);
* av := [v : [-, v] in comp_list];
* result := check_null_aggregate(av, lob, indices, node);
* result := ['array_ivalue', [v: [-, v] in comp_list],
* lob, lob + #comp_list - 1];
* else
*/
result = const_new(CONST_OM);
/* end if; */
break;
case(as_character_literal):
result = const_new(CONST_STR);
break;
case(as_un_op):
result = fold_unop(node);
break;
case(as_in):
opn = N_AST1(node);
op_range = N_AST2(node);
result = eval_qual_range(opn, N_TYPE(op_range));
if (is_const_constraint_error(result))
result = test_expr(FALSE);
else if (!is_const_om(result))
result = test_expr(TRUE);
break;
case(as_notin):
opn = N_AST1(node);
n2 = N_AST2(node);
result = eval_qual_range(opn, N_TYPE(n2));
if (is_const_constraint_error(result))
result = test_expr(TRUE);
else if (!is_const_constraint_error(result))
result = test_expr(FALSE);
break;
case(as_op):
result = fold_op(node);
break;
case(as_call):
{
int i;
Tuple arg_list;
Const arg;
opn = N_AST1(node);
result = const_new(CONST_OM); /* in general not static */
arg_list = N_LIST(N_AST2(node)); /* but can fold actuals. */
for (i = 1; i <= tup_size(arg_list); i++)
arg = const_fold((Node)arg_list[i]);
if (N_KIND(opn) == as_simple_name) {
sym = ALIAS(N_UNQ(opn));
if (sym != (Symbol)0 && is_literal(sym))
/* replace call by actual value of literal */
result = eval_lit_map(sym);
}
}
break;
case(as_parenthesis):
/* If the parenthesised expression is evaluable, return
* its value. Otherwise leave it parenthesised.
*/
opn = N_AST1(node);
result = const_fold(opn);
break;
case(as_qual_range):
opn = N_AST1(node);
op_type = N_TYPE(node);
result = eval_qual_range(opn, op_type);
if (is_const_constraint_error(result)) {
create_raise(node, symbol_constraint_error);
result = const_new(CONST_OM);
}
break;
case(as_qual_index):
eval_static(N_AST1(node));
result = const_new(CONST_OM);
break;
case(as_attribute):
case(as_range_attribute):
/* use separate procedure for C */
result = fold_attr(node);
break;
case(as_qualify):
if (fold_context)
result = const_fold(N_AST2(node));
else
/* in the context of a conformance check, keep qualification.*/
result = const_new(CONST_OM);
break;
/* Type conversion:
* /TBSL/ These conversions are not properly checked!
*/
case(as_convert):
/* use separate procedure for C */
result = fold_convert(node);
break;
case(as_array_aggregate):
/* This is treated in the expander.*/
result = const_new(CONST_OM);
break;
case(as_record_aggregate):
result = const_new(CONST_OM);
break;
case(as_selector): /*TBSL Case for discriminants needed */
expn = N_AST1(node);
eval_static(expn);
return const_new(CONST_OM);
case(as_slice):
expn = N_AST1(node);
discr_range = N_AST2(node);
eval_static(expn);
eval_static(discr_range);
return const_new(CONST_OM);
case(as_row): /* Not folded for now.*/
/* p1 := check_const_val(op1);
* if is_value(op1) then
* result := ['array_ivalue', [op1(2)], 1, 1];
* else
*/
return const_new(CONST_OM);
case(as_index):
expn = N_AST1(node);
index_list = N_AST2(node);
eval_static(expn);
FORTUP(index = (Node), N_LIST(index_list), ft1)
eval_static(index);
ENDFORTUP(ft1);
return const_new(CONST_OM);
default:
result = const_new(CONST_OM);
}
if (result->const_kind != CONST_OM)
insert_and_prune(node, result);
return result;
}
static Const fold_unop(Node node) /*;fold_unop*/
{
Node opn, oplist;
Const result, op1;
int op1_kind;
Symbol sym;
opn = N_AST1(node);
oplist = N_AST2(node);
op1 = const_fold((Node) (N_LIST(oplist))[1]);
if (is_const_om(op1)) return op1;
op1_kind = op1->const_kind;
sym = N_UNQ(opn);
if (sym == symbol_addui) {
/* the "+" can be ignored if it is used as a unary op */
result = op1;
}
else if (sym == symbol_addufl) {
result = op1;
}
else if (sym == symbol_addufx) {
result = op1;
}
else if (sym == symbol_subui ||
sym == symbol_subufl || sym == symbol_subufx) {
if (is_simple_value(op1)) {
if (sym == symbol_subui) {
if (is_const_int(op1)) {
if (INTV(op1) == ADA_MIN_INTEGER) {
create_raise(node, symbol_constraint_error);
result = const_new(CONST_OM);
}
else {
result = int_const(-INTV(op1));
}
}
else if (is_const_uint(op1))
result = uint_const(int_umin(UINTV(op1)));
else chaos("eval:subui bad type");
}
else if (sym == symbol_subufl) {
const_check(op1, CONST_REAL);
result = real_const(-REALV(op1));
}
}
else {
const_check(op1, CONST_RAT);
result= rat_const(rat_umin(RATV(op1)));
}
}
else if ( sym == symbol_not) {
if (is_simple_value (op1)) {
if (op1_kind == CONST_INT)
result = int_const(1-INTV(op1)); /*bnot in setl */
else chaos("fold_unop: bad kind");
}
else { /*TBSL*/
result = const_new(CONST_OM);
}
}
else if ( sym == symbol_absi ||
sym == symbol_absfl || sym == symbol_absfx) {
if (is_simple_value(op1)) {
if (sym == symbol_absi) {
if (op1_kind == CONST_INT) result = int_const(abs(INTV(op1)));
else if (op1_kind == CONST_UINT)chaos("fold_unit absi in uint");
else chaos("fold_unop: bad kind");
}
else if (sym == symbol_absfl) {
result = real_const(fabs(REALV(op1)));
}
}
else {
result= rat_const(rat_abs(RATV(op1)));
}
}
return result;
}
static Const fold_op(Node node) /*;fold_op*/
{
Node opn, arg1, arg2, oplist;
Const result, op1, op2, tryc;
Symbol sym, op_name;
int *uint;
int rm;
Tuple tup;
int res, overflow;
opn = N_AST1(node);
oplist = N_AST2(node);
tup = N_LIST(oplist);
arg1 = (Node) tup[1];
arg2 = (Node) tup[2];
op1 = const_fold(arg1);
op2 = const_fold(arg2);
op_name = N_UNQ(opn);
/* If either operand raises and exception, so does the operation */
if (N_KIND(arg1) == as_raise) {
copy_attributes(arg1, node);
return const_new(CONST_OM);
}
if (N_KIND(arg2) == as_raise
&& op_name != symbol_andthen && op_name != symbol_orelse) {
copy_attributes(arg2, node);
return const_new(CONST_OM);
}
if (is_const_om(op1) || (is_const_om(op2)
&& (op_name != symbol_in || op_name != symbol_notin))) {
return const_new(CONST_OM);
}
sym = op_name;
if ( sym == symbol_addi || sym == symbol_addfl) {
if (sym == symbol_addi) {
res = word_add(INTV(op1), INTV(op2), &overflow);
if (overflow) {
create_raise(node, symbol_constraint_error);
result = const_new(CONST_OM);
}
else result = int_const(res);
}
else
result = real_const(REALV(op1) + REALV(op2));
}
else if ( sym == symbol_addfx) {
const_check(op1, CONST_RAT);
const_check(op2, CONST_RAT);
result= rat_const(rat_add(RATV(op1), RATV(op2)));
}
else if ( sym == symbol_subi) {
if (is_const_int(op1)) {
if (is_const_int(op2)) {
res = word_sub(INTV(op1), INTV(op2), &overflow);
if (overflow) {
create_raise(node, symbol_constraint_error);
result = const_new(CONST_OM);
}
else result = int_const(res);
}
else {
chaos("fold_op: subi operand types");
}
}
}
else if (sym == symbol_subfl) {
result = real_const(REALV(op1) - REALV(op2));
}
else if ( sym == symbol_subfx) {
const_check(op1, CONST_RAT);
const_check(op2, CONST_RAT);
result= rat_const(rat_sub(RATV(op1), RATV(op2)));
}
else if ( sym == symbol_muli) {
#ifdef TBSL
-- need to check for overflow and convert result back to int if not
-- note that low-level setl is missing calls to check_overflow that
-- are present in high-level and should be in low-level as well
result = int_mul(int_fri(op1), int_fri(op2));
#endif
/* until overflow check in */
const_check(op1, CONST_INT);
const_check(op2, CONST_INT);
res = word_mul(INTV(op1), INTV(op2), &overflow);
if (overflow) {
create_raise(node, symbol_constraint_error);
result = const_new(CONST_OM);
}
else result = int_const(res);
}
else if ( sym == symbol_mulfl) {
const_check(op1, CONST_REAL);
const_check(op2, CONST_REAL);
if ((fabs(REALV(op1)) < ADA_SMALL_REAL)
|| (fabs(REALV(op2)) < ADA_SMALL_REAL)) {
result = real_const(0.0);
}
else if (log(fabs(REALV(op1))) +
log(fabs(REALV(op2))) > ADA_MAX_REAL) {
create_raise(node, symbol_constraint_error);
return const_new(CONST_OM);
}
else
result = real_const(REALV(op1) * REALV(op2));
}
else if ( sym == symbol_mulfx) {
const_check(op1, CONST_RAT);
const_check(op2, CONST_RAT);
result = rat_const(rat_mul(RATV(op1), RATV(op2)));
}
else if (sym == symbol_mulfxi || sym == symbol_mulfli) {
const_check(op1, CONST_RAT);
const_check(op2, CONST_RAT);
result = rat_const(rat_fri(int_mul(num(RATV(op1)), UINTV(op2)),
den(RATV(op1))));
}
else if (sym == symbol_mulifx) {
const_check(op1, CONST_UINT);
const_check(op2, CONST_RAT);
result = rat_const(rat_fri(int_mul(UINTV(op1), num(RATV(op2))),
den(RATV(op2))));
}
else if (sym == symbol_divi) {
if (INTV(op2)== 0) {
create_raise(node, symbol_constraint_error);
return const_new(CONST_OM);
}
result = int_const(INTV(op1) / INTV(op2));
}
else if (sym == symbol_divfl) {
const_check(op2, CONST_REAL);
if (fabs(REALV(op2)) < ADA_SMALL_REAL) {
create_raise(node, symbol_constraint_error);
return const_new(CONST_OM);
}
else if (fabs(REALV(op1)) < ADA_SMALL_REAL) {
const_check(op1, CONST_REAL);
result = real_const(0.0);
}
else if (log(fabs(REALV(op1))) -
log(fabs(REALV(op2))) >log(ADA_MAX_REAL)) {
create_raise(node, symbol_constraint_error);
return const_new(CONST_OM);
}
else {
result = real_const(REALV(op1)
/ REALV(op2));
}
}
else if (sym == symbol_divfx) {
/* TBSL: note that rnum(rat2) is in long integer format */
if (int_eqz(num(RATV(op2)))) {
create_raise(node, symbol_constraint_error);
return const_new(CONST_OM);
}
result = rat_const(rat_div(RATV(op1), RATV(op2)));
}
else if (sym == symbol_divfxi || sym == symbol_divfli) {
const_check(op1, CONST_RAT);
if (is_const_int(op2)) {
if (!INTV(op2)) {
create_raise(node, symbol_constraint_error);
return const_new(CONST_OM); }
result = rat_const(rat_fri(num(RATV(op1)), int_mul(den(RATV(op1)),
int_fri(INTV(op2))))); }
/* Shouldn't be a rational
else if (is_const_rat(op2)) {
if (int_eqz(num(RATV(op2)))) {
create_raise(node, symbol_constraint_error);
return const_new(CONST_OM); }
result = rat_const(rat_div(RATV(op1), RATV(op2))); }
*/
else {
const_check(op2, CONST_UINT);
if (int_eqz(UINTV(op2))) {
create_raise(node, symbol_constraint_error);
return const_new(CONST_OM); }
result = rat_const(rat_fri(num(RATV(op1)), int_mul(den(RATV(op1)),
UINTV(op2))));
}
}
else if (sym == symbol_remi) {
if (INTV(op2) == 0) {
create_raise(node, symbol_constraint_error);
return const_new(CONST_OM);
}
result = int_const(INTV(op1) - (INTV(op1) / INTV(op2)) * INTV(op2));
}
else if (sym == symbol_modi) {
if (INTV(op2) == 0) {
create_raise(node, symbol_constraint_error);
return const_new(CONST_OM);
}
rm = INTV(op1) % INTV(op2);
if ((rm == 0) || (INTV(op2) > 0))
result = int_const(rm);
else
result = int_const(rm + INTV(op2));
}
else if (sym == symbol_expi) {
if (INTV(op2) < 0) {
create_raise(node, symbol_constraint_error);
return const_new(CONST_OM);
}
else {
if (is_const_int(op1))
uint = int_fri(INTV(op1));
else
chaos("expi: bad kind");
const_check(op2, CONST_INT);
result = int_const(int_toi(int_exp(uint, int_fri(INTV(op2)))));
}
}
else if (sym == symbol_expfl) {
const_check(op1, CONST_REAL);
const_check(op2, CONST_INT);
if ((fabs(REALV(op1)) < ADA_SMALL_REAL)
|| ((abs(INTV(op2)) * log (fabs( REALV(op1)))) > log(ADA_MAX_REAL))) {
create_raise(node, symbol_constraint_error);
return const_new(CONST_OM);
}
return const_new(CONST_OM);
#ifdef TBSL
-- need to find C form for **
pow(x, y) is x**y with x an y both double.
result = op1 ** op2;
#endif
}
else if ((sym == symbol_cat) || (sym == symbol_cat_ca)
|| (sym == symbol_cat_ac) || (sym == symbol_cat_cc)) {
/* /TBSL/ Bounds may not be correct!*/
/* [-, agg1, lb1, ub1] := op1;
* [-, agg2, lb2, ub2] := op2;
* agg := agg1 + agg2;
* lb := lb1 min lb2;
*/
result = const_new(CONST_OM);
}
else if (sym == symbol_and || sym == symbol_or || sym == symbol_xor) {
if (is_simple_value(op1)) {
if (N_UNQ(opn) == symbol_and) {
if (is_const_int(op1))
result = int_const(INTV(op1)&&INTV(op2));
else
chaos("fold_unop: bad kind");
}
else if (N_UNQ(opn) == symbol_or) {
if (is_const_int(op1))
result = int_const(INTV(op1)||INTV(op2));
else
chaos("fold_unop: or bad kind");
}
else if (N_UNQ(opn) == symbol_xor) {
result = test_expr((INTV(op1))!= (INTV(op2)));
}
else {
chaos("ERROR IN ES99");
}
}
}
else if (sym == symbol_andthen || sym == symbol_orelse) {
/* not static */
result = const_new(CONST_OM);
}
else if (sym == symbol_eq) {
#ifdef TBSN
if (is_universal_real(op1) && is_universal_real(op2))
result = test_expr(rat_eql(op1, op2));
else
result = test_expr(op1 == op2);
#endif
if (const_same_kind(op1, op2))
return test_expr(const_eq(op1, op2));
else return int_const(FALSE);
}
else if (sym == symbol_ne) {
#ifdef TBSN
if (is_universal_real(op1) && is_universal_real(op2)) {
result = test_expr(rat_neq(op1, op2));
}
else {
/*TBSL: do we need two cases here */
if (is_const_int(op1))
result = int_const(INTV(op1) != INTV(op2));
else if (is_const_real(op1))
result = test_expr((REALV(op1) != REALV(op2)));
else
chaos("error in ne case in const_fold");
}
#endif
if (const_same_kind(op1, op2))
return test_expr(const_ne(op1, op2));
else return int_const(FALSE);
}
else if (sym == symbol_lt) {
if (is_simple_value(op1)) {
#ifdef TBSN
if (is_const_int(op1)) {
result = int_const(INTV(op1) < INTV(op2));
}
else {
if (is_const_real(op1)) {
result = real_const(REALV(op1)
< REALV(op2));
}
else {
chaos("fold_unop: lt bad kind ");
}
}
#endif
if (const_same_kind(op1, op2))
return test_expr(const_lt(op1, op2));
else return int_const(FALSE);
}
/*TBSL need array types */
else if (is_const_rat (op1) && is_const_rat (op2)) {
result = test_expr(rat_lss (RATV (op1), RATV (op2)));
}
else {
result = const_new(CONST_OM);
}
}
else if (sym == symbol_le) {
if (is_simple_value(op1)) {
#ifdef TBSN
if (is_const_int(op1)) {
result = int_const(INTV(op1) <= INTV(op2));
}
else if (is_const_real(op1)) {
result = real_const(REALV(op1) <= REALV(op2));
}
else {
chaos("fold_op: le bad kind");
}
#endif
if (const_same_kind(op1, op2))
return test_expr(const_le(op1, op2));
else return int_const(FALSE);
}
else { /*TBSL need array types */
if (is_const_rat (op1) && is_const_rat (op2))
result = test_expr(rat_leq (RATV (op1), RATV (op2)));
else
result = const_new(CONST_OM);
}
}
else if (sym == symbol_gt) {
if (is_simple_value(op1)) {
#ifdef TBSN
if (is_const_int(op1)) {
result = int_const(INTV(op1) > INTV(op2));
}
else if (is_const_real(op1)) {
result = real_const(REALV(op1)
> REALV(op2));
}
else {
chaos("fold_op: gt bad kind");
}
#endif
if (const_same_kind(op1, op2))
return test_expr(const_gt(op1, op2));
else return int_const(FALSE);
}
else { /*TBSL need array types */
if (is_const_rat (op1) && is_const_rat (op2))
result = test_expr(rat_gtr (RATV (op1), RATV (op2)));
result = const_new(CONST_OM);
}
}
else if (sym == symbol_ge) {
if (is_simple_value(op1)) {
#ifdef TBSN
if (is_const_int(op1))
result = int_const(INTV(op1) >= INTV(op2));
else if (is_const_real(op1))
result = real_const(REALV(op1) >= REALV(op2));
else
chaos("fold op ge bad kind");
#endif
if (const_same_kind(op1, op2))
return test_expr(const_ge(op1, op2));
else
return int_const(FALSE);
}
else { /*TBSL need array types */
if (is_const_rat (op1) && is_const_rat (op2))
result = test_expr(rat_geq (RATV (op1), RATV (op2)));
result = const_new(CONST_OM);
}
}
else if (sym == symbol_in || sym == symbol_notin) {
specialize(arg1, N_TYPE(arg2)); /* ?? */
/* check whether this is correct, SETL is TYPE_OF, which is WRONG!!*/
if (N_KIND(arg2) != as_simple_name) {
result = const_new(CONST_OM); /* Could do better. */
}
else {
tryc = eval_qual_range(opn, N_UNQ(arg2));
if (is_const_constraint_error(tryc))
result = test_expr(op_name == symbol_notin);
else if (!is_const_om(tryc))
result= test_expr(op_name == symbol_in);
}
}
else {
printf("bad operator symbol: %s\n", nature_str(NATURE(sym)));
chaos("fold_op: bad operator");
}
return result;
}
static Const fold_attr(Node node) /*;fold_attr*/
{
Node attr_node, typ_node, arg_node, f_node, l_node, l_n, h_n;
Symbol typ1;
int attrkind, is_t_n, rv, i, len, max;
Const first, last, op1, result, lo, hi;
Tuple tsig, sig, l;
Span save_span;
attr_node = N_AST1(node);
typ_node = N_AST2(node);
arg_node = N_AST3(node);
/* Try to fold the prefix of the attribute*/
eval_static(typ_node);
/*attr = N_VAL(attr_node); -- should be dead 3-13-86 ds */
attrkind = (int) attribute_kind(node);
if (N_KIND(typ_node) != as_simple_name) {
/*Not for attribute COUNT. beware!*/
typ1 = N_TYPE(typ_node);
}
else {
typ1 = N_UNQ(typ_node);
}
is_t_n = is_type_node(typ_node);
/* For array attributes, we establish whether it is being
* applied to an object or to a type. The two operations
* are distinguished in the interpreter by prefix O_ or T_
*/
if ((attrkind == ATTR_T_FIRST || attrkind == ATTR_T_LAST
|| attrkind == ATTR_T_RANGE || attrkind == ATTR_T_LENGTH )
&& can_constrain(typ1) ) {
errmsg( "attribute cannot be applied to unconstrained array type",
"3.6.2", attr_node);
}
else if (attrkind == ATTR_T_SIZE || attrkind == ATTR_O_SIZE) {
node = size_attribute(node);
if (N_KIND(node) == as_ivalue) {
return (Const) N_VAL(node);
}
else {
return const_new(CONST_OM);
}
}
else if (attrkind == ATTR_BASE) {
save_span = get_left_span(node);
N_KIND(node) = as_simple_name;
/* clear attribute code so won't be taken as string*/
N_VAL(node) = (char *)0;
N_UNQ(node) = base_type(typ1);
set_span(node, save_span);
return const_new(CONST_OM);
}
if (!is_t_n)return const_new(CONST_OM);
/* This was needed in the high level, to prevent extra
* folding in non-static cases. It may be superfluous here
*/
/* Attributes that are functions take the base type */
if (attrkind == ATTR_BASE || attrkind == ATTR_POS || attrkind == ATTR_PRED
||attrkind == ATTR_SUCC || attrkind == ATTR_VAL
|| attrkind == ATTR_VALUE) {
N_UNQ(typ_node) = base_type(typ1);
}
if (arg_node != OPT_NODE) {
op1 = const_fold(arg_node);
if (is_const_om(op1))return const_new(CONST_OM);
}
/* They are evaluable statically only if the subtype typ1
* itself is static.
*/
if (is_type(typ1) && is_static_subtype(typ1)
|| is_task_type(TYPE_OF(typ1))
|| attrkind == ATTR_T_CONSTRAINED || attrkind == ATTR_O_CONSTRAINED) {
; /* try to evaluate */
}
else {
return const_new(CONST_OM); /* not static (RM 4.9 (8)*/
}
if (is_generic_type(typ1)) return const_new(CONST_OM);
if (is_static_subtype(typ1)) {
tsig = SIGNATURE(typ1);
f_node = (Node) tsig[2];
l_node = (Node) tsig[3];
first = const_fold(f_node);
last = const_fold(l_node);
}
/* Attributes of SCALAR types or ARRAY types: */
if (attrkind == ATTR_O_FIRST || attrkind == ATTR_T_FIRST)
result = first;
else if (attrkind == ATTR_O_LAST || attrkind == ATTR_T_LAST)
result = last;
else if ( attrkind == ATTR_O_LENGTH || attrkind == ATTR_T_LENGTH
|| attrkind == ATTR_O_RANGE || attrkind == ATTR_T_RANGE)
result = const_new(CONST_OM);
/* Attributes of DISCRETE types: */
else if (attrkind == ATTR_IMAGE) {
Symbol btyp1;
char *image;
Tuple tup;
int tsize;
btyp1 = root_type(typ1);
image = emalloct(10, "fold-attr");
if (btyp1 == symbol_integer) {
const_check(op1, CONST_INT);
if (INTV(op1) >= 0) sprintf(image, " %d", INTV(op1));
else sprintf(image, "%d", INTV(op1));
}
else {
/* image :=
* if exists [nam, v] in literal_map(btyp1) | op1 = v
* then nam else '' end;
*/
image = "";
tup = (Tuple) literal_map(btyp1);
tsize = tup_size(tup);
for (i = 1; i <= tsize; i += 2) {
const_check(op1, CONST_INT);
if ((int)tup[i+1] == INTV(op1)) {
image = strjoin(tup[i], "");
break;
}
}
}
N_KIND(node) = as_string_ivalue;
/* N_VAL(node) = [abs c : c in image]; */
tsize = strlen(image);
tup = tup_new(tsize);
for (i = 1; i <= tsize; i++)
tup[i] = (char *) image[i-1];
if (N_AST1_DEFINED(N_KIND(node))) N_AST1(node) = (Node) 0;
if (N_AST2_DEFINED(N_KIND(node))) N_AST2(node) = (Node) 0;
if (N_AST3_DEFINED(N_KIND(node))) N_AST3(node) = (Node) 0;
if (N_AST4_DEFINED(N_KIND(node))) N_AST4(node) = (Node) 0;
N_VAL(node) = (char *) tup;
result = const_new(CONST_OM);
}
else if (attrkind == ATTR_VALUE) {
chaos("value attrobute (eval.c)");
}
else if (attrkind == ATTR_POS) {
const_check(op1, CONST_INT);
result = uint_const(int_fri(INTV(op1))); /*$ES10*/
/* result = int_const(int_fri(op1)); */ /*$ES10*/
}
else if (attrkind == ATTR_VAL || attrkind == ATTR_PRED
|| attrkind == ATTR_SUCC) {
const_check(op1, CONST_INT);
rv = INTV(op1);
sig = SIGNATURE(base_type(typ1));
if (sig != (Tuple)0) {
l_n = (Node) sig[2];
h_n = (Node) sig[3];
}
else {
l_n = (Node) 0;
h_n = (Node) 0;
}
lo = const_fold(l_n);
hi = const_fold(h_n);
if (is_const_om(lo) || is_const_om(hi)) {
return const_new(CONST_OM);
}
if (attrkind == ATTR_PRED) {
const_check(lo, CONST_INT);
if (rv > INTV(lo)) rv -= 1;
else {
create_raise(node, symbol_constraint_error);
return const_new(CONST_OM);
}
}
else if (attrkind == ATTR_SUCC) {
const_check(hi, CONST_INT);
if (rv < INTV(hi)) rv += 1;
else {
create_raise(node, symbol_constraint_error);
return const_new(CONST_OM);
}
}
else if (attrkind == ATTR_VAL) {
const_check(lo, CONST_INT);
const_check(hi, CONST_INT);
if (rv < INTV(lo) || rv > INTV(hi)) {
create_raise(node, symbol_constraint_error);
return const_new(CONST_OM);
}
}
result = int_const(rv);
}
else if (attrkind == ATTR_WIDTH) {
int first_val, last_val, max_val;
if (root_type(typ1) == symbol_integer) {
if (is_const_om(first) || is_const_om(last))
chaos("eval WIDTH: unexpected const_kind");
const_check(first, CONST_INT);
const_check(last, CONST_INT);
/* In the case of a null range the Width is defined as 0.
* Otherwise it is defined as the maximum IMAGE length for
* all values of the subtype.
*/
if (INTV(first) > INTV(last))
result = uint_const(int_fri(0));
else {
char *val_str = emalloct(10, "fold-attr-1");
first_val = abs(INTV(first));
last_val = abs(INTV(last));
max_val = (first_val > last_val ? first_val : last_val);
sprintf(val_str, " %d", max_val);
result = uint_const(int_fri(strlen(val_str)));
efreet(val_str, "eval-fold-rat");
}
}
else {
/* Must find longest name in enumeration subtype. */
int v;
l = (Tuple) literal_map(root_type(typ1));
max = 0;
first_val = abs(INTV(first)); /* bounds of subtype */
last_val = abs(INTV(last));
for (i = 1; i <= tup_size(l); i += 2) {
len = strlen(l[i]);
v = (int)l[i+1];
if (len > max && v >= first_val && v <= last_val)
max = len;
}
result = uint_const(int_fri(max));
}
}
/* Miscellaneous attributes. */
/* The following attributes are of type universal integer.
* The current system ignores them, and passes them to the expander.
*/
else if (attrkind == ATTR_POSITION || attrkind == ATTR_FIRST_BIT
|| attrkind == ATTR_LAST_BIT || attrkind == ATTR_STORAGE_SIZE) {
result = const_new(CONST_OM);
}
else if (attrkind == ATTR_O_CONSTRAINED || attrkind == ATTR_T_CONSTRAINED) {
/* Attribute is true on constants and on -in- parameters */
if ((typ1 != (Symbol) 0) &&
NATURE(typ1) == na_constant || NATURE(typ1) == na_in) {
result = int_const(1);
}
else if (!is_generic_type(typ1)) {
/* it is false for private types with discriminants. */
result = int_const( !(is_record(typ1) && has_discriminants(typ1)
&& NATURE(typ1) != na_subtype));
}
else { /* run-time check */
result = const_new(CONST_OM);
}
}
else if (attrkind == ATTR_ADDRESS || attrkind == ATTR_TERMINATED
|| attrkind == ATTR_CALLABLE) {
result = const_new(CONST_OM);
}
else {
/* Attributes of FIXED and FLOATing point types:*/
result = eval_real_type_attribute(node);
}
return result;
}
static Const fold_convert(Node node) /*;fold_convert*/
{
Node typ2_node, opd_node;
Symbol typ1, typ2; /* type2 is target type */
Const opd, result;
typ2_node = N_AST1(node);
opd_node = N_AST2(node);
typ1 = root_type(N_TYPE(opd_node));
typ2 = root_type(N_UNQ(typ2_node));
opd = const_fold(opd_node);
if (is_const_om(opd)) {
return const_new(CONST_OM);
}
if (typ1 == symbol_integer) {
if (typ2 == symbol_integer) {
result = opd;
}
else if (typ2 == symbol_float) {
const_check(opd, CONST_INT);
result = real_const((float)INTV(opd));
}
else if (typ2 == symbol_universal_integer) {
const_check(opd, CONST_INT);
result = uint_const(int_fri(INTV(opd)));
}
else if (typ2 == symbol_universal_real
|| typ2 == symbol_universal_fixed || typ2 == symbol_dfixed) {
if (is_const_int(opd)) {
result = rat_const(rat_fri(int_fri(INTV(opd)), int_fri(1)));
}
else if (is_const_uint(opd)) {
result = rat_const(rat_fri(UINTV(opd), int_fri(1)));
}
else
chaos("const wrong type (eval.c)");
}
else
result = const_new(CONST_OM);
}
else if (typ1 == symbol_float) {
if (typ2 == symbol_integer || typ2 == symbol_universal_integer) {
Rational z;
int *x, *y;
const_check(opd, CONST_REAL);
z = rat_frr((double)(REALV(opd) + 0.5));
x = num(z);
y = den(z);
result = uint_const(int_quo(x, y));
}
else if (typ2 == symbol_float) {
result = opd;
}
else if (typ2 == symbol_dfixed || typ2 == symbol_universal_real
|| typ2 == symbol_universal_fixed) {
result = rat_const(rat_frr((double)REALV(opd)));
}
else
result = const_new(CONST_OM);
}
else if (typ1 == symbol_universal_integer) {
if (typ2 == symbol_integer)
/*
result = opd;
*/
result = int_const(int_toi(UINTV(opd)));
else if (typ2 == symbol_float) {
/* result = [opd, 1]; */
/* result = real_const((float) UINTV(opd)); */
/*result = rat_const(rat_new(UINTV(opd), int_fri(1))); */
result = const_new (CONST_OM);
}
else if (typ2 == symbol_universal_integer) {
result = opd;
}
else if ( typ2 == symbol_universal_real ||
typ2 == symbol_universal_fixed ||
typ2 == symbol_dfixed) {
result = rat_const(rat_fri(UINTV(opd), int_fri(1)));
}
else
result = const_new(CONST_OM);
}
else if (typ1 == symbol_universal_real || typ1 == symbol_universal_fixed
|| typ1 == symbol_dfixed) {
if (typ2 == symbol_float) {
result = real_const (rat_tor (RATV (opd), ADA_REAL_DIGITS));
if (arith_overflow) {
arith_overflow = FALSE;
create_raise (node, symbol_constraint_error);
result = const_new (CONST_OM);
}
}
else if (typ2 == symbol_universal_real
|| typ2 == symbol_universal_fixed || typ2 == symbol_dfixed) {
result = opd;
}
else if (typ2 == symbol_integer) {
const_check(opd, CONST_RAT);
result = int_const(rat_toi(RATV(opd)));
}
else
result = const_new(CONST_OM);
}
else
result = const_new(CONST_OM);
return result;
}
static Const eval_qual_range(Node op1, Symbol op_type) /*;eval_qual_range*/
{
/* This has been separated from the main body of const_fold because
* it is used for two differents operators: 'qual_range' proper,
* and 'in' and 'notin'
*
* If the expression is not static it return the former expression expn.
* If the expression evaluates to a ['raise', 'CONSTRAINT_ERROR'] because
* op1 is not in the range op2, it returns the string 'contraint_error'
* without emitting any warning; this is left to the caller
* responsibility.
*/
Node lo, hi;
Const op1_val, lo_val, hi_val;
int c_error;
Tuple numcon;
Rational rop1_val;
if (cdebug2 > 3) TO_ERRFILE("AT PROC : eval_qual_range");
op1_val = const_fold(op1);
if (op1_val->const_kind == CONST_OM)
return const_new(CONST_OM);
/* May just be a type name. */
if (is_scalar_type(op_type)) {
numcon = SIGNATURE(op_type);
if (numcon != (Tuple)0) {
lo = (Node) numcon[2];
hi = (Node) numcon[3];
}
else {
lo = (Node) 0;
hi = (Node) 0;
}
}
else
return const_new(CONST_OM);
/* If the argument is universal, convert it to
* standard representation. A qual_range indicates
* a constrained type, i.e. non-universal.
*/
if (is_universal_integer(op1_val)) {
const_check(op1_val, CONST_UINT);
op1_val = int_const(int_toi(UINTV(op1_val)));
if (arith_overflow) {
arith_overflow = 0;
return const_new(CONST_CONSTRAINT_ERROR);
}
}
else if (is_universal_real(op1_val)
&& (!is_fixed_type(root_type(op_type)))) {
const_check(op1_val, CONST_RAT);
op1_val = real_const(rat_tor(RATV(op1_val), ADA_REAL_DIGITS));
if (arith_overflow) {
arith_overflow = FALSE;
return const_new(CONST_CONSTRAINT_ERROR);
}
}
if (N_KIND(lo) != as_ivalue || N_KIND(hi) != as_ivalue) {
return const_new(CONST_OM);
}
else {
lo_val = (Const) N_VAL(lo);
hi_val = (Const) N_VAL(hi);
}
/* The overflow test done here in SETL version is done above after
* calls to arith routines in C version
*/
if (op_type == symbol_integer || op_type == symbol_float
|| op_type == symbol_dfixed || op_type == symbol_character
|| NATURE(op_type) == na_enum) {
/* Predefined types: value is already known to be in range.*/
return op1_val;
}
else {
/* At this point everything is known to be constant.
* If the constraint is obeyed, return the value without
* a range qualification. Otherwise emit a constraint
* exception.
*/
/* c_error = ( root_type(op_type) != symbol_dfixed ?
* (op1_val < lo_val) || (op1_val > hi_val)
*/
if (is_fixed_type(root_type(op_type))) {
if (op1_val->const_kind == CONST_RAT) {
const_check(op1_val, CONST_RAT);
const_check(lo_val, CONST_RAT);
const_check(hi_val, CONST_RAT);
c_error = (rat_lss(RATV(op1_val), RATV(lo_val))
|| rat_gtr(RATV(op1_val), RATV(hi_val)));
}
else if (op1_val->const_kind == CONST_REAL) {
rop1_val = rat_frr(REALV(op1_val));
const_check(lo_val, CONST_RAT);
const_check(hi_val, CONST_RAT);
c_error = (rat_lss(rop1_val, RATV(lo_val))
|| rat_gtr(rop1_val, RATV(hi_val)));
}
}
else if (op1_val->const_kind == CONST_INT) {
const_check(op1_val, CONST_INT);
const_check(lo_val, CONST_INT);
const_check(hi_val, CONST_INT);
c_error = (INTV(op1_val) < INTV(lo_val))
|| (INTV(op1_val) > INTV(hi_val));
}
else if (op1_val->const_kind == CONST_REAL) {
const_check(op1_val, CONST_REAL);
const_check(lo_val, CONST_REAL);
const_check(hi_val, CONST_REAL);
c_error = (REALV(op1_val) < REALV(lo_val))
|| (REALV(op1_val) > REALV(hi_val));
}
if (c_error) {
return const_new(CONST_CONSTRAINT_ERROR);
}
else {
return op1_val;
}
}
}
static Const eval_real_type_attribute(Node node) /*;eval_real_type_attribute*/
{
/*
* Static evaluation of real types characteristics
* ===============================================
*/
Node attr_node, arg_node, lo, hi, precision;
Const result, precision_const;
Tuple sig;
int kind, attrkind, static_bounds;
int fl_digits;
Rational delta, fx_low, fx_high, xdelta, small;
/* the following are macros in SETL, and should eventually be converted */
#define rat_1 rat_fri(int_fri(1), int_fri(1))
#define rat_2 rat_fri(int_fri(2), int_fri(1))
if (cdebug2 > 3) TO_ERRFILE("AT PROC : eval_real_type_attribute");
attr_node = N_AST1(node);
arg_node = N_AST2(node);
result = const_new(CONST_OM);
sig = SIGNATURE(N_UNQ(arg_node));
kind = (int) sig[1];
/*
* Part A : FLOATING POINT REAL
*
* For a floating point real type FL, we have the following
* basic informations:
* digits (SETL_integer)
* fl_high (SETL_real)
* fl_low (SETL_real)
*/
if (kind == CONSTRAINT_DIGITS) {
lo = (Node) sig[2];
hi = (Node) sig[3];
precision = (Node) sig[4];
precision_const = (Const) N_VAL(precision);
const_check(precision_const, CONST_INT);
fl_digits = INTV(precision_const);
attrkind = (int) attribute_kind(node);
/*
*
* FL'DIGITS --> universal_integer
*
* The minimum number of significant decimal digits.
*/
if (attrkind == ATTR_DIGITS) {
result = uint_const(int_fri(fl_digits));
}
/*
*
* FL'MANTISSA --> universal_integer
*
* The minimum number of binary digits required for DIGITS:
* ceil(fl_digits*log(10)/log(2))+1)
*
*/
else if (attrkind == ATTR_MANTISSA) {
result = uint_const(fl_mantissa(fl_digits));
}
/*
* FL'EPSILON --> universal_real
*
* The absolute value of the difference between the nuber 1.0
* and the next model number above :
* = 2.0**(1-FL'MANTISSA)
*/
else if (attrkind == ATTR_EPSILON) {
result = rat_const(rat_exp(rat_2, int_sub(int_fri(1),
fl_mantissa(fl_digits))));
}
/*
* FL'EMAX --> universal_integer
*
* The largest exponent value in binary canonical form:
* = 4*FL'MANTISSA
*/
else if (attrkind == ATTR_EMAX || attrkind == ATTR_SAFE_EMAX) {
result = uint_const(fl_emax(fl_digits));
}
/*
* FL'SMALL --> universal_real
*
* The smallest positive non-zero number :
* = 2.0**(- FL'EMAX -1)
*/
else if (attrkind == ATTR_SMALL || attrkind == ATTR_SAFE_SMALL) {
result = rat_const( rat_exp(rat_2,
int_umin(int_add(fl_emax(fl_digits), int_fri(1)))));
}
/*
* FL'LARGE --> universal_integer
*
* The largest positive number:
* = 2.0**FL'EMAX * (1.0 - 2.0**(-FL'MANTISSA))
*/
else if (attrkind == ATTR_LARGE || attrkind == ATTR_SAFE_LARGE) {
/* TBSL: check types, this looks wrong */
result = rat_const(rat_mul( rat_exp(rat_2, fl_emax(fl_digits)),
rat_sub(rat_1, rat_exp(rat_2,int_umin(fl_mantissa(fl_digits))))));
}
/*
* FL'SAFE_EMAX = FL'BASE'EMAX
* FL'SAFE_SMALL = FL'BASE'SMALL
* FL'SAFE_LARGE = FL'BASE'LARGE
*
* cf. FL'EMAX, FL'SMALL, FL'LARGE
*/
/*
* FL'MACHINE_ROUNDS --> boolean
*/
else if (attrkind == ATTR_MACHINE_ROUNDS) {
result = test_expr(FALSE);
}
/*
* FL'MACHINE_OVERFLOWS --> boolean
*/
else if (attrkind == ATTR_MACHINE_OVERFLOWS) {
result = test_expr(TRUE);
}
/*
* FL'MACHINE_RADIX --> universal_integer
*/
else if (attrkind == ATTR_MACHINE_RADIX) {
result = uint_const(int_fri(2));
}
/*
* FL'MACHINE_MANTISSA --> universal_integer
*/
else if (attrkind == ATTR_MACHINE_MANTISSA) {
result = uint_const(int_fri(24));
}
/*
* FL'MACHINE_EMAX --> universal_integer
*/
else if (attrkind == ATTR_MACHINE_EMAX) {
result = uint_const(int_fri(127));
}
/*
* FL'MACHINE_EMIN --> universal_integer
*/
/* We have to modified MACHINE_EMIN so that test c45524a de C4dep */
/* passes */
else if (attrkind == ATTR_MACHINE_EMIN) {
result = uint_const(int_fri(-127));
}
}
/*
* Part B : FIXED POINT REAL
*
* For a fixed point real type FX, we have the following basic
* informations:
* delta (universal_real)
* fx_low (universal_real)
* fx_high (universal_real)
* but the bounds may not be static...
*/
else if (kind == CONSTRAINT_DELTA) {
attrkind = (int) attribute_kind(node);
if (attrkind == ATTR_SAFE_LARGE || attrkind == ATTR_SAFE_SMALL)
sig = SIGNATURE(base_type(N_UNQ(arg_node)));
lo = (Node) sig[2];
hi = (Node) sig[3];
precision = (Node) sig[4];
static_bounds = (is_static_expr(lo) && is_static_expr(hi));
delta = RATV((Const) N_VAL(precision));
small = RATV((Const)N_VAL((Node)numeric_constraint_small(sig)));
if (static_bounds) {
eval_static(lo);
eval_static(hi);
const_check((Const)N_VAL(lo), CONST_RAT);
const_check((Const)N_VAL(hi), CONST_RAT);
fx_low = RATV((Const)N_VAL(lo));
fx_high = RATV((Const) N_VAL(hi));
}
/*
* FX'DELTA --> universal_real
*
* The absolute value of the error bound.
*/
if (attrkind == ATTR_DELTA) {
result = rat_const(delta);
}
/*
* FX'SMALL --> universal_real
*
* The largest power of 2 not greater than the delta:
* = 2.0**floor(log(delta)/log(2.0))
*/
else if (attrkind == ATTR_SMALL || attrkind == ATTR_SAFE_SMALL) {
result = rat_const(small);
}
/*
* FX'MANTISSA --> universal_integer
*
* The number of binary digits required:
* = ceil(log(max(abs(fx_high), abs(fx_low))/FX'SMALL)/log(2.0)))
*/
else if (attrkind == ATTR_MANTISSA) {
if (static_bounds) {
result=uint_const(int_fri(fx_mantissa(fx_high, fx_low, small)));
}
}
/*
* FX'LARGE --> universal_real
*
* The largest positive number :
* = (2.0**FX'MANTISSA - 1) * FX'SMALL
*/
else if (attrkind == ATTR_LARGE || attrkind == ATTR_SAFE_LARGE) {
if (static_bounds) {
result = rat_const(rat_mul( rat_sub(rat_exp(rat_2,
int_fri( fx_mantissa(fx_high, fx_low, small))), rat_1),
small));
}
}
/*
* FX'FORE --> universal_integer
*
* The minimum number of characters needed for the integer
* part of the decimal representation (including sign).
*/
else if (attrkind == ATTR_FORE) {
if (static_bounds) {
int *ivalue_10, *rat_n, *rat_d; /* Multi-precision numbers */
int ivalue_n;
Rational fx_maximum;
ivalue_10 = int_fri(10);
ivalue_n = 2;
fx_maximum = fx_max(fx_high, fx_low);
rat_n = num(rat_abs(fx_maximum));
rat_d = den(rat_abs(fx_maximum));
while (int_geq(int_quo(rat_n, rat_d), ivalue_10)) {
rat_d = int_mul(rat_d, ivalue_10);
ivalue_n += 1;
}
result = uint_const(int_fri(ivalue_n));
}
}
/*
* FX'AFT --> universal_integer
*
* The number of decimal digits needed after the decimal point
* = smallest n such that (10**N)*FX'DELTA >= 1.0
*/
else if (attrkind == ATTR_AFT) {
xdelta = delta;
result = uint_const(int_fri(1));
while (rat_lss(xdelta, rat_fri(int_fri(1), int_fri(10)))) {
xdelta = rat_mul(xdelta, rat_fri(int_fri(10), int_fri(1)));
UINTV(result)= int_add(UINTV(result), int_fri(1));
}
}
/*
* FX'SAFE_SMALL = FX'BASE'SMALL
* FX'SAFE_LARGE = FX'BASE'LARGE
*
* cf. FX'SMALL and FX'LARGE
*/
/*
* FX'MACHINE_ROUNDS --> boolean
*/
else if (attrkind == ATTR_MACHINE_ROUNDS) {
result = test_expr(TRUE);
}
/*
* FX'MACHINE_OVERFLOWS --> boolean
*/
else if (attrkind == ATTR_MACHINE_OVERFLOWS) {
result = test_expr(TRUE);
}
}
return result;
}
static Const check_overflow(Node node, Const x) /*check_overflow*/
{
/*
* Check_overflow tests its argument against ADA_MAX_INTEGER or
* ADA_MAX_REAL, returning the setl value of the argument or the
* raise NUMERIC_ERROR instruction. Universal integers and reals are
* converted to setl values.
*/
int attrkind;
Const result;
if (cdebug2 > 3) TO_ERRFILE("AT PROC : check_overflow");
return const_new(CONST_OM); /*TBSL: for initial chceckout */
#ifdef TBSL
if (!is_numeric(N_TYPE(node))
return;
else if (x == symbol_overflow) {
create_raise(node, symbol_constraint_error);
result = om;
}
else
attrkind = (int) attribute_kind(node); /*TBSL - check this ds 14 nov */
case(type(x)) {
if (streq(attr, "INTEGER")) {
/*if (abs(x) > ADA_MAX_INTEGER) {
This previous test was wrong due to disymetry */
if ((x> ADA_MAX_INTEGER) || (x < ADA_MIN_INTEGER)) {
create_raise(node, symbol_constraint_error);
result = om;
}
else
result = x;
}
else if (streq(attr, "REAL")) {
if (abs(x) > ADA_MAX_REAL) {
create_raise(node, symbol_constraint_error);
result = om;
}
else
result = x;
}
else if (streq(attr, "TUPLE")) {
if is_universal_integer(x) {
if ((res = int_toi(x)) == 'OVERFLOW') {
create_raise(node, symbol_constraint_error);
result = om;
}
else
result = res;
}
else
if ((res = rat_tor(x, ada_real_digits)) == 'OVERFLOW') {
create_raise(node, symbol_constraint_error);
result = om;
}
else
result = res;
else
; /* Not a numeric node */
}
return result;
#endif
}
static int *fl_mantissa(int fl_digits) /*;fl_mantissa*/
{
/*
* ceil(fl_digits*log(10)/log(2))+1)
*/
return (int_fri((int)ceil(((double)fl_digits*log(10.0))/log(2.0) + 1.0)));
}
static int *fl_emax(int fl_digits) /*;fl_emax*/
{
return int_mul(int_fri(4), fl_mantissa(fl_digits));
}
int is_universal_integer(Const x) /*;is_universal_integer*/
{
return is_const_uint(x);
}
int is_universal_real(Const x) /*;is_universal_real*/
{
return is_const_rat(x);
}
static void insert_and_prune(Node node, Const value) /*;insert_and_prune*/
{
/* When an expression tree can be constant-folded, it is reduced to a
* formattd value for the interpreter, and its descendants are dis-
* carded. The type has been established during type resolution.
*/
int nk;
Span savespan;
if (cdebug2 > 3) { }
nk = N_KIND(node);
savespan = get_left_span(node);
if (N_AST1_DEFINED(nk)) N_AST1(node) = (Node) 0;
if (N_AST4_DEFINED(nk)) N_AST4(node) = (Node) 0;
N_KIND(node) = as_ivalue;
N_UNQ(node) = (Symbol) 0; /* as_ivalue has no n_unq */
N_VAL(node) = (char *) value;
N_SPAN0(node) = savespan->line;
N_SPAN1(node) = savespan->col;
}
void create_raise(Node node, Symbol exception) /*;create_raise*/
{
/* This routine replaces the subtree at node by a -raise- operator
* with -exception- as its operand
*/
Node excp_node;
Node span_node;
if (cdebug2 > 3) TO_ERRFILE("AT PROC : create_raise");
warning(strjoin("Evaluation of expression will raise ",
ORIG_NAME(exception)), node);
excp_node = node_new(as_simple_name);
span_node = node_new(as_simple_name);
copy_span(node, excp_node);
copy_span(node, span_node);
N_UNQ(excp_node) = exception;
N_KIND(node) = as_raise;
N_AST1(node) = excp_node;
N_AST2(node) = span_node;
N_TYPE(node) = (Symbol)0;
return;
}
static Rational fx_max (Rational fx_high, Rational fx_low) /*;fx_max*/
{
if (rat_geq(rat_abs(fx_high), rat_abs(fx_low)))
return rat_abs(fx_high);
else
return rat_abs(fx_low);
}
static Const test_expr(int e) /*;test_expr*/
{
Const res;
res = const_new(CONST_INT);
INTV(res) = e;
return res;
}